package cn.lopr.mvc.frame.processors;

import cn.lopr.mvc.frame.annotaion.Autowired;
import cn.lopr.mvc.frame.annotaion.Repository;
import cn.lopr.mvc.frame.annotaion.Service;
import cn.lopr.mvc.frame.util.MyBatisUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.Map;

import static cn.lopr.util.StringUtils.toLowerFirstCase;

/**
 * @author shuangyang7
 * @date 2021/7/21 9:18
 */
public class AutowiredProcessor {

    public void doRuntimeAutowiredWithHttpReqAndHttpResp(Field[] fields, Object currentServiceBean,
                                                         HttpServletRequest req, HttpServletResponse resp) throws IllegalAccessException {
        for (Field field : fields) {
            if (!field.isAnnotationPresent(Autowired.class)) {
                continue;
            }
            field.setAccessible(true);
            if ("HttpServletRequest".equals(field.getType().getSimpleName())) {
                field.set(currentServiceBean, req);
            } else if ("HttpServletResponse".equals(field.getType().getSimpleName())) {
                field.set(currentServiceBean, resp);
            }
        }
    }

    public void doRuntimeAutowiredWithDataSource(Field[] fields, Object currentServiceBean,
                                                 Map<String, Class<?>> iocRepositoryMaps, Map<String, Object> iocMap) {
        for (Field field : fields) {
            if (!field.isAnnotationPresent(Autowired.class)) {
                continue;
            }
            if (field.getType().isAnnotationPresent(Service.class)) {
                String fieldName = toLowerFirstCase(field.getType().getSimpleName());
                Object iocObj = iocMap.get(fieldName);
                Field[] declaredFieldsIocObj = iocObj.getClass().getDeclaredFields();
                doRuntimeAutowiredWithDataSource(declaredFieldsIocObj, iocObj, iocRepositoryMaps, iocMap);
                continue;
            }

            if (!field.getType().isAnnotationPresent(Repository.class)) {
                continue;
            }
            field.setAccessible(true);
            Autowired autowired = field.getAnnotation(Autowired.class);
            String beanName = autowired.value().trim();
            if ("".equals(beanName)) {
                beanName = field.getType().getSimpleName();
                beanName = toLowerFirstCase(beanName);
            }
            Class<?> mapperClass = iocRepositoryMaps.get(beanName);
            try {
                field.set(currentServiceBean, MyBatisUtils.getMapper(mapperClass));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    public void doAutowiredInterceptor(Map<String, Object> interceptorMaps, Map<String, Object> iocMap) {
        doAutowired(interceptorMaps, iocMap);
    }

    /**
     * 4、依赖注入
     */
    public void doAutowiredIoc(Map<String, Object> iocMap, Map<String, Object> iocMap2) {
        doAutowired(iocMap, iocMap2);
    }

    public void doAutowired(Map<String, Object> map, Map<String, Object> iocMap) {
        if (map.isEmpty()) {
            return;
        }

        for (Map.Entry<String, Object> entry : map.entrySet()) {

            Field[] fields = entry.getValue().getClass().getDeclaredFields();

            for (Field field : fields) {

                if (!field.isAnnotationPresent(Autowired.class)) {
                    continue;
                }
                if (field.getType().getSimpleName().equals("HttpServletRequest")
                        || field.getType().getSimpleName().equals("HttpServletResponse")) {
                    continue;
                }

                Autowired autowired = field.getAnnotation(Autowired.class);
                String beanName = autowired.value().trim();
                if ("".equals(beanName)) {
                    beanName = field.getType().getSimpleName();
                    beanName = toLowerFirstCase(beanName);
                }
                field.setAccessible(true);

                try {
                    field.set(entry.getValue(), iocMap.get(beanName));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }


}
